package com.mashuai.utils.toolkit.core.msMp;

import cn.hutool.db.Db;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.*;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.mashuai.utils.base.MsAssertUtils;
import com.mashuai.utils.base.MsIocUtils;
import com.mashuai.utils.base.MsReflexUtils;
import com.mashuai.utils.toolkit.achieve.MsExegesis;
import com.mashuai.utils.toolkit.inter.IMsDbSaveBeforeIntercept;
import com.mashuai.utils.toolkit.inter.functionalInterface.mp.FMsDbGetWrappers;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.session.SqlSession;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: mashuai
 * @ClassName: MsDb
 * @Description: 静态方式调用mybatisplus的service层方法，避免在业务层引入Mapper层、Service层进行crud方法调用
 */
@MsExegesis("静态方式调用mybatisplus的service层方法，避免在业务层引入Mapper层、Service层进行crud方法调用")
public class MsDb {

    private static final Log log = LogFactory.getLog(MsDb.class);

    private MsDb() {

    }


    @MsExegesis("直接获取mybatis的最底层SqlSession，用来操作万能sql，但是不建议，存在sql注入风险")
    public static SqlSession getSqlSession(){
        SqlSession sqlSession = MsIocUtils.getBean(SqlSession.class);
        return sqlSession;
    }
    /**
     * @param val
     * @param column
     * @param throwMsg
     * @param clz
     */
    @MsExegesis("检测某个字段值是否已经存在，如果存在抛出Msg信息。val@检测值，column@MsUser::getCode，msg@异常提示信息，clz@T.class")
    public static <T, R, V> void au_columnValueValid(V val, SFunction<T, R> column, String throwMsg, Class<T> clz) {
        SqlHelper.execute(clz, mapper -> {
            LambdaQueryWrapper<T> qw = Wrappers.lambdaQuery();
            qw.in(column, val);
            Long count = mapper.selectCount(qw);
            if (count != 0) {
                MsAssertUtils.throwException(throwMsg);
            }
            return null;
        });
    }
    @MsExegesis("查询列表，如果空集合抛出throwMsg信息。MsDb.au_getList('如果找不到抛出异常',MsUser.class, ew -> ew.eq(MsUser::getCode, 'mashuai'))")
    public static <T, R, V> List<T> au_getListZeroValid(String throwMsg, Class<T> clz, FMsDbGetWrappers<T> ewFuc) {
        LambdaQueryWrapper<T> qw = Wrappers.lambdaQuery();
        ewFuc.wrappers(qw);
        List<T> list = list(qw, clz);
        if (list.size()==0){
            MsAssertUtils.throwException(throwMsg);
        }
        return list;
    }

    @MsExegesis("查询列表，根据自定义Wrapper条件获取列表。MsDb.au_getList(MsUser.class, ew -> ew.eq(MsUser::getCode, 'mashuai'))")
    public static <T> List<T> au_getList(Class<T> clz, FMsDbGetWrappers<T> ewFuc) {
        LambdaQueryWrapper<T> qw = Wrappers.lambdaQuery();
        ewFuc.wrappers(qw);
        return list(qw, clz);
    }

    /**
     * 根据字段值获取列表
     * <p>
     * /**
     * 保存前拦截器，对数据额外处理
     */
    private static <T> void saveBeforeIntercept(T t, Class<T> clz) {
        saveBeforeIntercept(Arrays.asList(t), clz);
    }

    /**
     * 保存前拦截器，对数据额外处理
     */
    private static <T> void saveBeforeIntercept(List<T> list, Class<T> clz) {
        String[] beanNames = MsIocUtils.getBeanNames(IMsDbSaveBeforeIntercept.class);
        if (beanNames != null && beanNames.length != 0) {
            IMsDbSaveBeforeIntercept beforeIntercept = (IMsDbSaveBeforeIntercept) MsIocUtils.getBean(beanNames[0], IMsDbSaveBeforeIntercept.class);
            if (beforeIntercept.handleCondition(clz)) {
                beforeIntercept.beforeSave(list, clz);
            }
        }
    }


    @MsExegesis("插入一条记录")
    public static <T> boolean insert(T entity) {
        if (Objects.isNull(entity)) {
            return false;
        }
        @SuppressWarnings("unchecked")
        Class<T> entityClass = (Class<T>) entity.getClass();
        saveBeforeIntercept(entity, entityClass);
        Integer result = SqlHelper.execute(entityClass, baseMapper -> baseMapper.insert(entity));
        return SqlHelper.retBool(result);
    }

    @MsExegesis("根据 ID 选择修改")
    public static <T> boolean updateById(T entity) {
        if (Objects.isNull(entity)) {
            return false;
        }
        @SuppressWarnings("unchecked")
        Class<T> entityClass = (Class<T>) entity.getClass();
        saveBeforeIntercept(entity, entityClass);
        return SqlHelper.execute(entityClass, baseMapper -> SqlHelper.retBool(baseMapper.updateById(entity)));
    }

    @MsExegesis("TableId 注解存在更新记录，否插入一条记录")
    public static <T> boolean saveOrUpdate(T entity) {
        return checkIsAdd(entity) ? insert(entity) : updateById(entity);
    }

    @MsExegesis("isAdd=true=新增，isAdd=false=根据id更新")
    public static <T> boolean saveOrUpdate(T entity, boolean isAdd) {
        MsAssertUtils.throwException("请指定插入或更新类型");
        return isAdd ? insert(entity) : updateById(entity);
    }

    /**
     * @param entity        实体对象
     * @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
     */
    @MsExegesis("根据 whereEntity 条件，更新记录")
    public static <T> boolean update(T entity, AbstractWrapper<T, ?, ?> updateWrapper, Class<T> tClass) {
        saveBeforeIntercept(entity, tClass);
        return SqlHelper.execute(tClass, baseMapper -> SqlHelper.retBool(baseMapper.update(entity, updateWrapper)));
    }

    @MsExegesis(" 根据 UpdateWrapper 条件，更新记录 需要设置sqlset")
    public static <T> boolean update(AbstractWrapper<T, ?, ?> updateWrapper, Class<T> tClass) {
        return SqlHelper.execute(tClass, baseMapper -> SqlHelper.retBool(baseMapper.update(null, updateWrapper)));
    }

    @MsExegesis("根据实体(ID)删除")
    public static <T> boolean removeById(T entity) {
        if (Objects.isNull(entity)) {
            return false;
        }
        @SuppressWarnings("unchecked")
        Class<T> entityClass = (Class<T>) entity.getClass();
        return SqlHelper.execute(entityClass, baseMapper -> SqlHelper.retBool(baseMapper.deleteById(entity)));
    }

    @MsExegesis("传入class对象后根据id值删除")
    public static <T> boolean removeById(Serializable id, Class<T> entityClass) {
        return SqlHelper.execute(entityClass, baseMapper -> SqlHelper.retBool(baseMapper.deleteById(id)));
    }


    @MsExegesis("根据class对象，和queryWrapper条件，删除记录")
    public static <T> boolean remove(AbstractWrapper<T, ?, ?> queryWrapper, Class<T> tClass) {
        return SqlHelper.execute(tClass, baseMapper -> SqlHelper.retBool(baseMapper.delete(queryWrapper)));
    }


    @MsExegesis("删除（根据ID 批量删除）")
    public static <T> boolean removeByIds(Collection<? extends Serializable> list, Class<T> entityClass) {
        return SqlHelper.execute(entityClass, baseMapper -> SqlHelper.retBool(baseMapper.deleteBatchIds(list)));
    }

    /**
     * 根据 columnMap 条件，删除记录
     *
     * @param columnMap   表字段 map 对象
     * @param entityClass 实体类
     */
    @MsExegesis("根据 columnMap 条件，删除记录")
    public static <T> boolean removeByMap(Map<String, Object> columnMap, Class<T> entityClass) {
        return SqlHelper.execute(entityClass, baseMapper -> SqlHelper.retBool(baseMapper.deleteByMap(columnMap)));
    }


    /**
     * 插入（批量）
     *
     * @param entityList 实体对象集合
     */
    @MsExegesis("批量插入")
    public static <T> boolean insertBatch(Collection<T> entityList) {
        return insertBatch(entityList, IService.DEFAULT_BATCH_SIZE);
    }

    /**
     * 插入（批量）
     *
     * @param entityList 实体对象集合
     * @param batchSize  插入批次数量
     */
    public static <T> boolean insertBatch(Collection<T> entityList, int batchSize) {
        if (CollectionUtils.isEmpty(entityList)) {
            return false;
        }
        Class<T> entityClass = getEntityClass(entityList);
        saveBeforeIntercept(new ArrayList<>(entityList), entityClass);
        Class<?> mapperClass = ClassUtils.toClassConfident(getTableInfo(entityClass).getCurrentNamespace());
        String sqlStatement = SqlHelper.getSqlStatement(mapperClass, SqlMethod.INSERT_ONE);
        return SqlHelper.executeBatch(entityClass, LogFactory.getLog(Db.class), entityList, batchSize, (sqlSession, entity) -> sqlSession.insert(sqlStatement, entity));
    }

    /**
     * 批量修改或插入
     *
     * @param entityList 实体对象集合
     */
    public static <T> boolean saveOrUpdateBatch(Collection<T> entityList) {
        return saveOrUpdateBatch(entityList, IService.DEFAULT_BATCH_SIZE);
    }

    /**
     * 批量修改插入
     *
     * @param entityList 实体对象集合
     * @param batchSize  每次的数量
     */
    public static <T> boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
        if (CollectionUtils.isEmpty(entityList)) {
            return false;
        }
        Class<T> entityClass = getEntityClass(entityList);
        saveBeforeIntercept(new ArrayList<>(entityList), entityClass);
        TableInfo tableInfo = getTableInfo(entityClass);
        Class<?> mapperClass = ClassUtils.toClassConfident(tableInfo.getCurrentNamespace());
        String keyProperty = tableInfo.getKeyProperty();
        Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for primary key from entity!");
        return SqlHelper.saveOrUpdateBatch(entityClass, mapperClass, LogFactory.getLog(Db.class), entityList, batchSize, (sqlSession, entity) -> {
            Object idVal = tableInfo.getPropertyValue(entity, keyProperty);
            return StringUtils.checkValNull(idVal)
                    || CollectionUtils.isEmpty(sqlSession.selectList(SqlHelper.getSqlStatement(mapperClass, SqlMethod.SELECT_BY_ID), entity));
        }, (sqlSession, entity) -> {
            MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
            param.put(Constants.ENTITY, entity);
            sqlSession.update(SqlHelper.getSqlStatement(mapperClass, SqlMethod.UPDATE_BY_ID), param);
        });
    }


    /**
     * 根据ID 批量更新
     *
     * @param entityList 实体对象集合
     */
    @MsExegesis("根据ID 批量更新")
    public static <T> boolean updateBatchById(Collection<T> entityList) {
        return updateBatchById(entityList, IService.DEFAULT_BATCH_SIZE);
    }

    /**
     * 根据ID 批量更新
     *
     * @param entityList 实体对象集合
     * @param batchSize  更新批次数量
     */
    public static <T> boolean updateBatchById(Collection<T> entityList, int batchSize) {
        if (entityList.size() == 0) return false;
        Class<T> entityClass = getEntityClass(entityList);
        saveBeforeIntercept(new ArrayList<>(entityList), entityClass);
        TableInfo tableInfo = getTableInfo(entityClass);
        String sqlStatement = SqlHelper.getSqlStatement(ClassUtils.toClassConfident(tableInfo.getCurrentNamespace()), SqlMethod.UPDATE_BY_ID);
        return SqlHelper.executeBatch(entityClass, LogFactory.getLog(Db.class), entityList, batchSize, (sqlSession, entity) -> {
            MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
            param.put(Constants.ENTITY, entity);
            sqlSession.update(sqlStatement, param);
        });
    }


    /**
     * 保存或更新，如果id为null为新增，否则去库里查询一次如果不存在值就新增，存在就保存
     * isAdd：true-为新增，false-为更新
     **/
    private static <T> boolean checkIsAdd(T entity) {
        if (Objects.isNull(entity)) {
            return false;
        }
        @SuppressWarnings("unchecked")
        Class<T> entityClass = (Class<T>) entity.getClass();
        TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
        Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
        String keyProperty = tableInfo.getKeyProperty();
        Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
        Object idVal = tableInfo.getPropertyValue(entity, tableInfo.getKeyProperty());
        //判断id值是否为空，如果不为空进行一些字段回填
        //idAdd：true-为新增，false-为更新
        boolean isAdd = StringUtils.checkValNull(idVal) || Objects.isNull(getById((Serializable) idVal, entityClass));
        return isAdd;
    }


    /**
     * 根据 ID 查询
     *
     * @param id          主键ID
     * @param entityClass 实体类
     */
    public static <T> T getById(Serializable id, Class<T> entityClass) {
        return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectById(id));
    }

    /**
     * 根据 id集合批量查询
     *
     * @param ids         主键ID
     * @param entityClass 实体类
     * @author mashuai
     */
    public static <T> List<T> getByIds(List ids, Class<T> entityClass) {
        return SqlHelper.execute(entityClass, baseMapper -> {
            QueryWrapper<Object> query = Wrappers.query();
            List<Field> classFieldA = MsReflexUtils.getClassFieldA(entityClass, TableId.class);
            query.in(classFieldA.get(0).getName(), ids);
            return baseMapper.selectList((Wrapper<T>) query);
        });
    }


    /**
     * 根据 Wrapper，查询一条记录 <br/>
     * <p>结果集，如果是多个会抛出异常，随机取一条加上限制条件 wrapper.last("LIMIT 1")</p>
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    public static <T> T getOne(AbstractWrapper<T, ?, ?> queryWrapper, Class<T> tClass) {
        return getOne(queryWrapper, tClass, true);
    }

    /**
     * 根据 Wrapper，查询一条记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     * @param throwEx      有多个 result 是否抛出异常
     */
    public static <T> T getOne(AbstractWrapper<T, ?, ?> queryWrapper, Class<T> tClass, boolean throwEx) {
//        Class<T> entityClass = getEntityClass(queryWrapper);
        if (throwEx) {
            return SqlHelper.execute(tClass, baseMapper -> baseMapper.selectOne(queryWrapper));
        }
        return SqlHelper.execute(tClass, baseMapper -> SqlHelper.getObject(log, baseMapper.selectList(queryWrapper)));
    }


    /**
     * 根据 Wrapper，查询一条记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    public static <T> Map<String, Object> getMap(AbstractWrapper<T, ?, ?> queryWrapper, Class<T> tClass) {
        return SqlHelper.execute(tClass, baseMapper -> SqlHelper.getObject(log, baseMapper.selectMaps(queryWrapper)));
    }

    /**
     * 查询总记录数
     *
     * @param entityClass 实体类
     * @see Wrappers#emptyWrapper()
     */
    public static <T> long count(Class<T> entityClass) {
        return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectCount(null));
    }

    /**
     * 根据 Wrapper 条件，查询总记录数
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    public static <T> long count(AbstractWrapper<T, ?, ?> queryWrapper, Class<T> tClass) {
        return SqlHelper.execute(tClass, baseMapper -> baseMapper.selectCount(queryWrapper));
    }

    /**
     * 查询列表
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    public static <T> List<T> list(AbstractWrapper<T, ?, ?> queryWrapper, Class<T> clazz) {
        //Class<T> entityClass = getEntityClass(queryWrapper);
        return SqlHelper.execute(clazz, baseMapper -> baseMapper.selectList(queryWrapper));
    }

    /**
     * 查询所有
     *
     * @param entityClass 实体类
     * @see Wrappers#emptyWrapper()
     */
    public static <T> List<T> list(Class<T> entityClass) {
        return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectList(null));
    }

    /**
     * 查询（根据 columnMap 条件）
     *
     * @param columnMap   表字段 map 对象
     * @param entityClass 实体类
     */
    public static <T> List<T> listByMap(Map<String, Object> columnMap, Class<T> entityClass) {
        return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectByMap(columnMap));
    }

    /**
     * 查询（根据ID 批量查询）
     *
     * @param idList      主键ID列表
     * @param entityClass 实体类
     */
    public static <T> List<T> listByIds(Collection<? extends Serializable> idList, Class<T> entityClass) {
        return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectBatchIds(idList));
    }

    /**
     * 查询列表
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    public static <T> List<Map<String, Object>> listMaps(AbstractWrapper<T, ?, ?> queryWrapper, Class<T> clazz) {
        return SqlHelper.execute(clazz, baseMapper -> baseMapper.selectMaps(queryWrapper));
    }

    /**
     * 查询所有列表
     *
     * @param entityClass 实体类
     * @see Wrappers#emptyWrapper()
     */
    public static <T> List<Map<String, Object>> listMaps(Class<T> entityClass) {
        return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectMaps(null));
    }

    /**
     * 查询全部记录
     *
     * @param entityClass 实体类
     */
    public static <T> List<T> listObjs(Class<T> entityClass) {
        return listObjs(entityClass, i -> i);
    }

    /**
     * 根据 Wrapper 条件，查询全部记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    public static <T> List<Object> listObjs(AbstractWrapper<T, ?, ?> queryWrapper, Class<T> clazz) {
        return SqlHelper.execute(clazz, baseMapper -> baseMapper.selectObjs(queryWrapper));
    }

    /**
     * 根据 Wrapper 条件，查询全部记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     * @param mapper       转换函数
     */
    public static <T, V> List<V> listObjs(AbstractWrapper<T, ?, ?> queryWrapper, Class<T> clazz, SFunction<? super T, V> mapper) {
        return SqlHelper.execute(clazz, baseMapper -> baseMapper.selectList(queryWrapper).stream().map(mapper).collect(Collectors.toList()));
    }

    /**
     * 查询全部记录
     *
     * @param entityClass 实体类
     * @param mapper      转换函数
     */
    public static <T, V> List<V> listObjs(Class<T> entityClass, SFunction<? super T, V> mapper) {
        return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectList(null).stream().map(mapper).collect(Collectors.toList()));
    }

    /**
     * 无条件翻页查询
     *
     * @param page        翻页对象
     * @param entityClass 实体类
     * @see Wrappers#emptyWrapper()
     */
    public static <T, E extends IPage<Map<String, Object>>> E pageMaps(E page, Class<T> entityClass) {
        return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectMapsPage(page, null));
    }

    /**
     * 翻页查询
     *
     * @param page         翻页对象
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    public static <T, E extends IPage<Map<String, Object>>> E pageMaps(E page, AbstractWrapper<T, ?, ?> queryWrapper, Class<T> tClass) {
        return SqlHelper.execute(tClass, baseMapper -> baseMapper.selectMapsPage(page, queryWrapper));
    }

    /**
     * 无条件翻页查询
     *
     * @param page        翻页对象
     * @param entityClass 实体类
     * @see Wrappers#emptyWrapper()
     */
    public static <T> IPage<T> page(IPage<T> page, Class<T> entityClass) {
        return SqlHelper.execute(entityClass, baseMapper -> baseMapper.selectPage(page, null));
    }

    /**
     * 翻页查询
     *
     * @param page         翻页对象
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    public static <T> IPage<T> page(IPage<T> page, AbstractWrapper<T, ?, ?> queryWrapper, Class<T> tClass) {
        return SqlHelper.execute(tClass, baseMapper -> baseMapper.selectPage(page, queryWrapper));
    }

    /**
     * <p>
     * 根据updateWrapper尝试更新，否继续执行saveOrUpdate(T)方法
     * 此次修改主要是减少了此项业务代码的代码量（存在性验证之后的saveOrUpdate操作）
     * </p>
     *
     * @param entity 实体对象
     */
    public static <T> boolean saveOrUpdate(T entity, AbstractWrapper<T, ?, ?> updateWrapper, Class<T> tClass) {
        return update(entity, updateWrapper, tClass) || saveOrUpdate(entity);
    }

    /**
     * 根据 Wrapper，查询一条记录
     *
     * @param queryWrapper 实体对象封装操作类
     * @param mapper       转换函数
     */
    public static <T, V> V getObj(AbstractWrapper<T, ?, ?> queryWrapper, Class<T> tClass, SFunction<? super T, V> mapper) {
        return SqlHelper.execute(tClass, baseMapper -> mapper.apply(baseMapper.selectOne(queryWrapper)));
    }

    /**
     * 从集合中获取实体类型
     *
     * @param entityList 实体集合
     * @param <T>        实体类型
     * @return 实体类型
     */
    @SuppressWarnings("unchecked")
    protected static <T> Class<T> getEntityClass(Collection<T> entityList) {
        Class<T> entityClass = null;
        for (T entity : entityList) {
            if (entity != null && entity.getClass() != null) {
                entityClass = (Class<T>) entity.getClass();
                break;
            }
        }
        Assert.notNull(entityClass, "error: can not get entityClass from entityList");
        return entityClass;
    }

    /**
     * 从wrapper中尝试获取实体类型
     *
     * @param queryWrapper 条件构造器
     * @param <T>          实体类型
     * @return 实体类型
     */
    @SuppressWarnings("unchecked")
    protected static <T> Class<T> getEntityClass(AbstractWrapper<T, ?, ?> queryWrapper) {
        Class<T> entityClass = queryWrapper.getEntityClass();
        if (entityClass == null) {
            T entity = queryWrapper.getEntity();
            if (entity != null) {
                entityClass = (Class<T>) entity.getClass();
            }
        }
        Assert.notNull(entityClass, "error: can not get entityClass from wrapper");
        return entityClass;
    }

    /**
     * 获取表信息，获取不到报错提示
     *
     * @param entityClass 实体类
     * @param <T>         实体类型
     * @return 对应表信息
     */
    protected static <T> TableInfo getTableInfo(Class<T> entityClass) {
        return Optional.ofNullable(TableInfoHelper.getTableInfo(entityClass)).orElseThrow(() -> ExceptionUtils.mpe("error: can not find TableInfo from Class: \"%s\".", entityClass.getName()));
    }
}
